<?php
/**
 * $Id: match.class.php 73 2005-12-01 21:32:12Z tito $
 *
 * FGS is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


class fgsMatchs {

	/**
	 * getLast : get last match
	 * @return an array with some match attribute :
	 *  id : id of match
	 *  game_name : name of game
	 *  game_version : version of game
	 *  game_datecreate : creation date of game (timestamp)
	 *  nb_players : number of player in match
	 *  match_datecreate : create date of match (timestamp)
	 *  match_locked : indicate if match is locked or not
	 *  match_duration : duration of match (seconds)
	 *  match_status : status of a match
	 *  match_status_ret : status of a match (int)
	 */
	function getLast($limit = 5, $start = false, $filters = false) {
		if ($start !== false && $start < 1) 
			$start = 1;
		$filter = array();
		$filter[] = 'ffme.player >= 0';
		if ($filters !== false) {
			if (isset($filters['login']))
				$filter[] = sprintf('(ffme.key="PlayerLogin" AND ffme.value="%s")', $filters['login']);
			if (isset($filters['nostalled']))
				$filter[] = '(ffm.is_locked OR (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(ffg.dt_create) <= 180))';
		}
		$query = sprintf('
			SELECT
				ffm.id_auto as id,
				fg.name as game_name,
				fg.gid as game_gid,
				ffg.version as game_version,
				ffg.dt_create as game_datecreate,
				MAX(ffme.player) as nb_players,
				ffm.is_locked as match_locked
			FROM fgs_fgsd_match ffm
			INNER JOIN fgs_fgsd_games ffg
				ON ffm.id_fgsd_game = ffg.id
			LEFT JOIN fgs_games fg
				ON fg.gid = ffg.name
			LEFT JOIN fgs_fgsd_match_entry ffme
				ON ffme.id_match = ffm.id_auto
			WHERE
				%s
			GROUP BY ffm.id_auto
			ORDER BY ffm.id_auto 
			%s',
			implode(' AND ', $filter),
			$start !== false ? 
				sprintf('LIMIT %d,%d', $start, $limit) :
				($limit !== false ? sprintf('DESC LIMIT %d', $limit) : 'DESC')
		);

		$sql = fgs::sql();
		$sql->query($query);
		if ($sql->nbRows()) {
			$matchs = $sql->fetchAll();
			$entries = fgsMatchs::get(array_keys($matchs), array('"GameTimeCreated"', '"GameLastUpdate"'));
			foreach ($matchs as $k => $match) {
				$matchs[$k]['match_duration'] = (int)($entries[$k]['GameLastUpdate'] - $entries[$k]['GameTimeCreated']);
				$status = fgsMatchs::interpretStatus($match['match_locked'], $entries[$k]['GameLastUpdate']);
				$matchs[$k]['match_status_ret'] = $status['ret'];
				$matchs[$k]['match_status'] = $status['msg'];
				$matchs[$k]['match_datecreate'] = (int)($entries[$k]['GameTimeCreated']);
			}
			if ($start !== false)
				return array_reverse($matchs, true);
			return $matchs;
		}
		return false;
	}

	/**
	 * get matchs count
	 * @return match count
	 */
	function getCount() {

		$query = '
			SELECT COUNT(*) as num
			FROM fgs_fgsd_match ffm';
		$sql = fgs::sql();
		$sql->query($query);
		$infos = $sql->getline();

		return $infos['num'];

	}

	/**
	 * interpretStatus() return string of status
	 * @param is_locked boolean of lock
	 * @param last_update timestamp of last update
	 * @return string description of status
	 */
	function interpretStatus($is_locked, $last_update) {

		$msg = tr('Running');
		$ret = 0;

		if ($is_locked) {
			$msg = tr('Locked');
			$ret = 1;
		} else if ((time() - $last_update) > 60*3) {
			$msg = tr('Stalled');
			$ret = -1;
		}

		return array('ret' => $ret, 'msg' => $msg);

	}

	/**
	 * get() get attributes of match
	 * @param id game id (integer | array of integers)
	 * @param gamekeys filter on attributes
	 * @return list of matchs
	 */
	function get($id, $gamekeys = null) {

		$where = array();
		if (is_array($id))
			$where[] = sprintf('ffm.id_auto IN (%s)', implode(', ', $id));
		else
			$where[] = sprintf('ffm.id_auto = %d', $id);

		if (is_array($gamekeys))
			$where[] = sprintf('ffme.key IN (%s)', implode(', ', $gamekeys));

		$query = sprintf('
			SELECT
				ffg.name as ffg_name,
				ffg.port as ffg_port,
				ffg.version as ffg_version,
				ffg.dt_create as ffg_datecreate,
				ffm.is_locked as ffm_locked,
				ffme.*
			FROM fgs_fgsd_match_entry ffme
			LEFT JOIN fgs_fgsd_match ffm
				ON ffme.id_match = ffm.id_auto
			LEFT JOIN fgs_fgsd_games ffg
				ON ffm.id_fgsd_game = ffg.id
			WHERE
				%s',
			implode(' AND ', $where)
		);


		$sql = fgs::sql();
		$sql->query($query);
		$infos = $sql->fetchAll();
		if (!$infos)
			return false;

		$ret = array();
		if (is_array($gamekeys)) {
			foreach ($infos as $info)
				$ret[$info['id_match']][$info['key']] = $info['value'];
		} else {
			$ret = array();
			foreach ($infos as $info)
				$ret[$info['player']][$info['key']] = $info['value'];
		}

		return $ret;

	}

	/**
	 * @param id_match id of a match
	 * @param id_game id of current game
	 * @return array of match attributes or false if failed
	 */
	function exist($id_match, $id_fgsd_game) {

		// check if match exist
		$query = sprintf('
			SELECT id_auto, is_locked
			FROM fgs_fgsd_match
			WHERE
				id_match = "%d"
				AND id_fgsd_game = "%d"
			ORDER BY id_auto DESC
			LIMIT 1', 
			$id_match, 
			$id_fgsd_game
		);

		$sql = fgs::sql();
		$sql->query($query);

		if ($sql->nbrows() != 1)
			return false;

		return $sql->getline();
	}

	/**
	 * update() update match attribute
	 * @param fgsd valid array of fgsd attributes
	 * @param id game id
	 * @param game array of current game attributes
	 * @param players 2 dimensionnal array of players attributes
	 * @param timestamp current timestamp
	 */
	function update($fgsd, $id, $game, $players, $timestamp) {

		// prepare variables
		$query_args = array();
		$sql = fgs::sql();

		// check if match exist
		$match = fgsMatchs::exist($id, $fgsd['ffg_id']);

		// if the match already exist, use it
		if (false !== $match) {

			// match lock ?
			if ($match['is_locked'])
				return false;

			$match_id = $match['id_auto'];

		// if no match exist, create one
		} else {

			$query = sprintf('
				INSERT INTO fgs_fgsd_match
				SET
					id_match = "%d",
					id_fgsd_game = "%d",
					is_locked = 0', 
					$id, 
					$fgsd['ffg_id']
			);

			$sql->query($query);
			$match_id = $sql->getLastId();

			// add time of creation
			$query_args[] = array(
				'match_id' => $match_id,
				'player'   => 0,
				'key'      => 'GameTimeCreated',
				'value'    => time()
			);
		}

		// add last update
		$query_args[] = array(
			'match_id' => $match_id,
			'player'   => 0,
			'key'      => 'GameLastUpdate',
			'value'    => time());

		// add all given match informations
		foreach ($game as $key => $value) {
			$query_args[] = array(
				'match_id' => $match_id,
				'player'   => 0,
				'key'      => $key,
				'value'    => $value
			);
		}

		// add all given player informations
		foreach ($players as $player_id => $player_info) {

			foreach ($player_info as $key => $value) {
				$query_args[] = array(
					'match_id' => $match_id,
					'player'   => $player_id,
					'key'      => $key,
					'value'    => $value);
			}

			// if we get PlayerCram, add PlayerID at this time
			if (array_key_exists('PlayerCram', $player_info) &&
				array_key_exists('_PlayerSalt', $player_info)) {

				$query = sprintf('
					SELECT users.id
					FROM fgs_sessions
					LEFT JOIN users
						ON users.login = fgs_sessions.login
					WHERE SHA1(CONCAT(fgs_sessions.user_sid, \'%s\')) = "%s"',
						fgsSql::escapeStr($player_info['_PlayerSalt']),
						fgsSql::escapeStr($player_info['PlayerCram']));

				$sql->query($query);
				$player_id = fgsUsers::getIdFromSaltAndCram($player_info['_PlayerSalt'], $player_info['PlayerCram']);
				if ($player_id > 0) {
					$query_args[] = array(
						'match_id' => $match_id,
						'player'   => $player_id,
						'key'      => 'PlayerID',
						'value'    => $player_id
					);
				}

			}
		}

		if (count($query_args)) {

			// construct query
			$query = 'REPLACE INTO fgs_fgsd_match_entry(`id_match`, `player`, `key`, `value`) VALUES';
			$query2 = array();

			foreach ($query_args as $elt) {
				$query2[] = sprintf('("%d", "%d", "%s", "%s")',
					$elt['match_id'],
					$elt['player'],
					fgsSql::escapeStr($elt['key']),
					fgsSql::escapeStr($elt['value'])
				);
			}

			$query .= implode(', ', $query2);

			$sql->query($query);

			$affrows = $sql->affrows();
			if ($affrows > 0)
				fgsLog::log(1, sprintf('[%s] change %d entries for match %d', $fgsd['fgsd_name'], count($query_args), $id));
			else 
				fgsLog::log(1, sprintf('[%s] no change when update match %d entries', $fgsd['fgsd_name'], $id));
				
			return $affrows;

		}
		
		return 0;

	}

	/**
	 * lock() lock a match
	 * @param fgsd valid array of fgsd attributes
	 * @param id match id
	 */
	function lock($fgsd, $id) {

		// check if match exist
		$match = fgsMatchs::exist($id, $fgsd['ffg_id']);
		if (false === $match)
			return false;
		
		// match lock ?
		if ($match['is_locked'])
			return false;

		// lock match	
		$query = sprintf('
			UPDATE fgs_fgsd_match
			SET is_locked = 1
			WHERE id_auto = "%d"', 
			$match['id_auto']
		);

		$sql = fgs::sql();
		$sql->query($query);

		fgsLog::log(1, sprintf('[%s] lock match %d', $fgsd['fgsd_name'], $id));

		return true;
	}

}

?>
